package com.neidetcher.tuml;

import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;

import org.jdom.DocType;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Namespace;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

import com.neidetcher.tuml.model.Message;
import com.neidetcher.tuml.model.Model;
import com.neidetcher.tuml.model.Object;

public class SequenceDiagramSvgRenderEngine implements RenderEngine
{
   private String fileNamePrefix = null;
   private Model model = null;
   
   public String getExtension()
   {
      return "svg";
   }

   public void setFileNamePrefix(String fileNamePrefixIn)
   {
      fileNamePrefix = fileNamePrefixIn;
   }
   
   public void setModel(Model modelIn)
   {
      model = modelIn;
   }
   private Namespace svgNs = Namespace.getNamespace("http://www.w3.org/2000/svg");
   private int width;
   private int height;
   private int RECTANGLE_WIDTH = 140;
   private String FONT_COLOR = "black";
   
   public void render(int widthIn, int heightIn) throws Exception
   {
      width = widthIn;
      height = heightIn;
      
      Element svg = new Element("svg", svgNs);

      svg.setAttribute("width",  ""+widthIn);
      svg.setAttribute("height", ""+heightIn);
      
      int xSpacing = (widthIn - 20) / model.getObjects().size(); 
      
      System.out.println("*********************** xSpacing: " + xSpacing);
      
      Document doc = new Document(svg);
      doc.setDocType(new DocType(
            "svg", 
            "-//W3C//DTD SVG 1.1//EN",
            "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"));
      
      //////// draw the objects on the top and all the life lines
      int ii = 0;
      for (Object currObject: model.getObjects())
      {
         int xStart = 10 + (xSpacing * ii++);
         System.out.println("xStart: " + xStart);
         
         int xLine = xStart + (RECTANGLE_WIDTH / 2);
         currObject.setXLifeLine(xLine); // we use this for rendering the messages later    
         
         List<Element> elements = newObjectElements(currObject, xStart, xLine);
         
         for(Element currElement: elements)
         {
            svg.addContent(currElement);
         }
      }
      
      //////// draw the messages
      int jj = 0;
      int messagesSize = model.getMessages().size();
      int ySpacing = 0;
      if (messagesSize != 0)
      {
         ySpacing = (heightIn - 60) / model.getMessages().size();
      }
      
      for(Message currMessage: model.getMessages())
      {
         int yStart = 90 + (ySpacing * jj++);
         
         List<Element> elements = newMessageElements(currMessage, yStart, model.getObjects());
         
         for(Element currElement: elements)
         {
            svg.addContent(currElement);
         }
      }
      
      // create the file and write svg to it
      Format format = Format.getPrettyFormat();
      XMLOutputter outputter = new XMLOutputter(format);
      FileOutputStream output = new FileOutputStream(fileNamePrefix + "." + getExtension());
      outputter.output(doc, output);
   }
   
   public List<Element> newObjectElements(Object objectIn, int xStart, int xLine)
   {
      List<Element> elements = new ArrayList<Element>();
      
      Element rectElement = new Element("rect", svgNs);
      rectElement.setAttribute("x",      ""+xStart);
      rectElement.setAttribute("y",      "10");
      rectElement.setAttribute("width",  "" + RECTANGLE_WIDTH);
      rectElement.setAttribute("height", "40");
      rectElement.setAttribute("style", "fill:lightyellow; stroke:gray;stroke-width:1px;");
      elements.add(rectElement);

      Element lineElement = new Element("line", svgNs);
      lineElement.setAttribute("x1", ""+xLine);
      lineElement.setAttribute("y1", "50");
      lineElement.setAttribute("x2", ""+xLine);
      lineElement.setAttribute("y2", ""+(height - 10));
      lineElement.setAttribute("style", "stroke:gray;stroke-width:1px;");
      elements.add(lineElement);
      
      Element textElement = new Element("text", svgNs);
      textElement.setAttribute("x", ""+xLine);
      textElement.setAttribute("y", "30");
      textElement.setAttribute("font-family", "Arial");
      textElement.setAttribute("font-size", "12");
      textElement.setAttribute("fill", FONT_COLOR);
      textElement.setAttribute("style", "text-anchor: middle; stroke-dasharray: 9, 5;");
      textElement.setText(objectIn.getName() + ":" + objectIn.getType());
      elements.add(textElement);
      
      return elements;
   }
   
   public List<Element> newMessageElements(Message messageIn, int yStartIn, List<Object> objectsIn)
   {
      System.out.println("processing: " + messageIn.toString());
      List<Element> elements = new ArrayList<Element>();
      
      int fromX = 10;
      int toX   = 10;
      for(Object currObject: objectsIn)
      {
         if(currObject.getName().equals(messageIn.getFromObject()))
         {
            System.out.println("from object: " + currObject.getName());
            fromX = currObject.getXLifeLine();
         }
         else if (currObject.getName().equals(messageIn.getToObject()))
         {
            System.out.println("to object: " + currObject.getName());
            toX = currObject.getXLifeLine();
         }
      }
      
      System.out.println("~~~~~~~~~~~~~~~~~ from x: " + fromX);
      System.out.println("~~~~~~~~~~~~~~~~~ to   x: " + toX);
      
      Element lineElement = new Element("line", svgNs);
      lineElement.setAttribute("x1", ""+fromX);
      lineElement.setAttribute("y1", ""+yStartIn);
      lineElement.setAttribute("x2", ""+toX);
      lineElement.setAttribute("y2", ""+yStartIn);
      lineElement.setAttribute("style", "stroke:gray;stroke-width:1px;");
      elements.add(lineElement);
      
      // text
      Element textElement = new Element("text", svgNs);
      textElement.setAttribute("x", ""+ (fromX + 2));
      textElement.setAttribute("y", ""+ (yStartIn - 7));
      textElement.setAttribute("font-family", "Arial");
      textElement.setAttribute("font-size", "12");
      textElement.setAttribute("fill", FONT_COLOR);
      textElement.setAttribute("style", "text-anchor: left; stroke-dasharray: 9, 5;");
      textElement.setText(
            messageIn.getToMethod() + "(" + 
            messageIn.getArguments() + "):" + 
            messageIn.getReturnType());
      elements.add(textElement);
      
      // arrow
      Element arrowTop = new Element("line", svgNs);
      arrowTop.setAttribute("x1", ""+(toX - 5));
      arrowTop.setAttribute("y1", ""+(yStartIn - 5));
      arrowTop.setAttribute("x2", ""+toX);
      arrowTop.setAttribute("y2", ""+yStartIn);
      arrowTop.setAttribute("style", "stroke:gray;stroke-width:1px;");
      elements.add(arrowTop);

      Element arrowBottom = new Element("line", svgNs);
      arrowBottom.setAttribute("x1", ""+(toX - 5));
      arrowBottom.setAttribute("y1", ""+(yStartIn + 5));
      arrowBottom.setAttribute("x2", ""+toX);
      arrowBottom.setAttribute("y2", ""+yStartIn);
      arrowBottom.setAttribute("style", "stroke:gray;stroke-width:1px;");
      elements.add(arrowBottom);
      
      return elements;
   }
}
